home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
MacGzip 1.0
/
source
/
GNU
/
gzip.c
< prev
next >
Wrap
Text File
|
1995-12-30
|
33KB
|
1,393 lines
/*
* gzip.c for MacGzip 1.0
* SPDsoft, August 22, 1995
* very little to do with original gzip.c (gzip.c.cln in this distribution)
*/
/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
* Copyright (C) 1992-1993 Jean-loup Gailly
* The unzip code was written and put in the public domain by Mark Adler.
* Portions of the lzw code are derived from the public domain 'compress'
* written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
* Ken Turkowski, Dave Mack and Peter Jannesen.
*
*/
#ifdef RCSID
static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
#endif
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <setjmp.h>
#include "tailor.h"
#include "MacIO.h"
#include "FileTypes.h"
#include "Prefs.h"
#include "Globals.h"
#include "GzErrors.h"
#include "GzPStrings.h"
#include "gzip.h"
#include "lzw.h"
#include "revision.h"
typedef RETSIGTYPE (*sig_type) OF((int));
#ifndef MAX_PATH_LEN
# define MAX_PATH_LEN 255 /* max pathname length */
#endif
#define PART_SEP "."
/* global buffers */
DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
DECLARE(ush, d_buf, DIST_BUFSIZE);
DECLARE(uch, window, 2L*WSIZE);
#ifndef MAXSEG_64K
DECLARE(ush, tab_prefix, 1L<<BITS);
#else
DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
#endif
/* local variables */
int macbinary = 0;
int ascii = 0; /* convert end-of-lines to local OS conventions */
int to_stdout = 0; /* output to stdout (-c) */
int decompress = 0; /* decompress (-d) */
int force = 0; /* don't ask questions, compress links (-f) */
int no_name = -1; /* don't save or restore the original file name */
int no_time = -1; /* don't save or restore the original file time */
int list = 0; /* list the file contents (-l) */
int verbose = 0; /* be verbose (-v) */
int quiet = 0; /* be very quiet (-q) */
int test = 0; /* test .gz file integrity */
char *progname ="gzip"; /* program name */
int maxbits = BITS; /* max bits per code for LZW */
int method = DEFLATED; /* compression method */
int level = 6; /* compression level */
int exit_code = OK; /* program exit code */
int save_orig_name; /* set if original name must be saved */
int last_member; /* set for .zip and .Z files */
int part_nb; /* number of parts in .gz file */
long time_stamp; /* original time stamp (modification time) */
long ifile_size; /* input file size, -1 for devices (debug only) */
char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
int z_len; /* strlen(z_suffix) */
long bytes_in; /* number of input bytes */
long bytes_out; /* number of output bytes */
long total_in = 0; /* input bytes for all files */
long total_out = 0; /* output bytes for all files */
char ifname[MAX_PATH_LEN]; /* input file name */
char ofname[MAX_PATH_LEN]; /* output file name */
int remove_ofname = 0; /* remove output file on error */
struct stat istat; /* status for input file */
int ifd; /* input file descriptor */
int ofd; /* output file descriptor */
unsigned insize; /* valid bytes in inbuf */
unsigned inptr; /* index of next byte to be processed in inbuf */
unsigned outcnt; /* bytes in output buffer */
jmp_buf env; /* for setjmp (do_exit) */
FSSpec ifs,
ofs;
/* local functions */
local void treat_file( FSSpec *fs );
local int create_outfile OF((void));
local char *get_suffix OF((char *name));
local int get_istat( FSSpec *ifs, struct stat *sbuf);
local int make_ofname OF((void));
local void shorten_name OF((char *name));
local int get_method OF((int in));
local int check_ofname OF((void));
local void copy_stat OF((struct stat *ifstat));
local void do_exit OF((int exitcode));
int (*work) OF((int infile, int outfile)) = zip; /* function to call */
local void reset_times (FSSpec *fs, struct stat *statb);
local Boolean init_globals( FSSpec *fs );
OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt );
OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt );
#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
int gzip ( FSSpec *fs );
/* ======================================================================== */
int gzip ( FSSpec *fs )
{
int file_count; /* number of files to precess */
int proglen; /* length of progname */
if ( setjmp(env) != 0)
{
/* this is executed upon process error */
return ERROR;
}
proglen = 4;
if (get_istat(fs, &istat) != OK) return ERROR;
if (init_globals( fs )) return ERROR;
ifs = *fs;
ofs = *fs;
/* By default, save name and timestamp on compression but do not
* restore them on decompression.
*/
if (no_time < 0) no_time = decompress;
if (no_name < 0) no_name = decompress;
file_count = 1;
if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX)
{
/* this should never happend (suffix is tested in PrefsDlg.c) */
DoError(INPUT_ERR, WARN_ERR, "%s: incorrect suffix '%s'", progname, z_suffix);
do_exit(ERROR);
}
/* if (do_lzw && !decompress) work = lzw; *//* not supported in gzip 1.2.4 */
/*
* Allocate all global buffers (for DYN_ALLOC option)
*/
ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
ALLOC(ush, d_buf, DIST_BUFSIZE);
ALLOC(uch, window, 2L*WSIZE);
#ifndef MAXSEG_64K
ALLOC(ush, tab_prefix, 1L<<BITS);
#else
ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
#endif
/* And get to work */
treat_file( &ifs );
/* do_list(-1, -1); *//* print totals */
do_exit(exit_code);
return exit_code; /* just to avoid lint warning */
}
/* ========================================================================
* Compress or decompress the given file
*/
local void treat_file( FSSpec *fs )
{
int imode;
if ( !decompress && macbinary )
ifile_size = istat.st_mbsize;
else
ifile_size = istat.st_size;
time_stamp = no_time ? 0 : istat.st_mtime;
/* Generate output file name. For -r and (-t or -l), skip files
* without a valid gzip suffix (check done in make_ofname).
*/
if (make_ofname() != OK) return;
/* Here we don't have the true output fname (when decompress)
* just the iname without the suffix. We will wait to 'create_outfile'
*/
if ( decompress )
{
imode = OM_RDONLY | OM_BINARY;
}
else
{
if ( macbinary == 1) imode = OM_RDONLY | OM_MACBINARY;
else if ( ascii == 1) imode = OM_RDONLY | OM_TEXT;
else imode = OM_RDONLY | OM_BINARY;
}
ifd = fs_open( fs, imode );
if (ifd == -1)
{
DoError(STDC_ERR, WARN_ERR, "%s: %s:", progname, ifname);
exit_code = ERROR;
return;
}
clear_bufs(); /* clear input and output buffers */
part_nb = 0;
if (decompress)
{
method = get_method(ifd); /* updates ofname if original given */
if (method < 0)
{
close(ifd);
return; /* error message already emitted */
}
}
/*
* Here we have enough info to set decompress flags.
*
* even if we are trying MacBinary, we should try to
* map the file, since MB translation can fail, if
* the file is not really a MB gziped file, and then we'll
* have to switch to the default mode.
*/
if (create_outfile() != OK) return;
/* Keep the name even if not truncated except with --no-name: */
if (!save_orig_name) save_orig_name = !no_name;
/*
* Open progress window...
*/
gApp.Working = TRUE;
SetMMString( "g%szip (%s) %s", decompress ? "un" : "" , macbinary ? "MBII" : ( ascii ? "ASCII" : "bin" ), ofname );
InitMovableModal( ifile_size, &fd_table[ifd].pos );
DoSystemTask();
/* Actually do the compression/decompression. Loop over zipped members.
*/
for (;;)
{
if ((*work)(ifd, ofd) != OK)
{
method = -1; /* force cleanup */
break;
}
if (!decompress || last_member || inptr == insize) break;
/* end of file */
method = get_method(ifd);
if (method < 0) break; /* error message already emitted */
bytes_out = 0; /* required for length check */
}
close(ifd);
DoSystemTask();
if ( close(ofd) )
{
write_error();
}
if (method == -1)
{
fs_unlink ( &ofs );
return;
}
copy_stat(&istat);
}
/* ========================================================================
* Create the output file. Return OK or ERROR.
* Try several times if necessary to avoid truncating the z_suffix. For
* example, do not create a compressed file of name "1234567890123."
* Sets save_orig_name to true if the file name has been truncated.
* IN assertions: the input file has already been open (ifd is set) and
* ofname has already been updated if there was an original name.
* OUT assertions: ifd and ofd are closed in case of error.
*/
/*
* MacGzip:
*
* if gApp.Prompt we must sfgetfile with ofname,
* anyway, if we are decompressing a MB file we only will know
* its name at the moment of create it.
*
*/
local int create_outfile()
{
int flags;
if (check_ofname() != OK)
{
close(ifd);
return ERROR;
}
/* set flags */
if ( decompress )
{
gSufMap.Found = FALSE;
ascii = 0;
macbinary = 0;
/* even if we are trying mb, we must check suffix mapping */
macbinary = gPrefs.Decompress.TryMB ? 1 : 0;
if ( gPrefs.Decompress.Mode == kDeco_MASCII )
{
gSufMap.Binary = FALSE;
gSufMap.MacFile = FALSE;
}
else
{
gSufMap.Binary = TRUE;
gSufMap.MacFile = FALSE;
}
if (( gPrefs.Decompress.Keys ) && ( gApp.KeysMode != 0 ))
{
switch ( gApp.KeysMode )
{
case kAppKeyASCII:
gSufMap.Binary = FALSE;
gSufMap.MacFile = FALSE;
macbinary = 0;
break;
case kAppKeyBin:
gSufMap.Binary = TRUE;
gSufMap.MacFile = FALSE;
macbinary = 0;
break;
case kAppKeyMBin:
gSufMap.Binary = TRUE;
gSufMap.MacFile = TRUE;
macbinary = 1;
break;
default:
DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
break;
}
}
else
{
if ( gPrefs.Decompress.IC )
{
ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTIC );
}
else if ( gPrefs.Decompress.Fetch )
{
ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTFetch );
}
}
if ( ! gSufMap.Found )
{
if ( gSufMap.Binary )
{
gSufMap.Type = gPrefs.Decompress.BinType;
gSufMap.Creator = gPrefs.Decompress.BinCreator;
}
else
{
gSufMap.Type = 'TEXT';
gSufMap.Creator = gPrefs.Decompress.TextCreator;
}
}
ascii = gSufMap.Binary ? 0 : 1;
flags = OM_WRONLY | ( ascii ? OM_TEXT : OM_BINARY );
if ( macbinary ) flags |= OM_MACBINARY;
DefCreator = gSufMap.Creator;
DefType = gSufMap.Type;
}
else /* compress */
{
flags = OM_WRONLY | OM_BINARY;
DefCreator = 'Gzip'; /* externals in MacIO.c */
DefType = 'Gzip';
}
/* Create the output file */
remove_ofname = 1;
ofd = fs_open( &ofs, flags );
if (ofd == -1)
{
DoError(STDC_ERR, WARN_ERR, "Can't open %s", ofname );
close(ifd);
exit_code = ERROR;
return ERROR;
}
return OK;
}
/***************************************************************************
* Return a pointer to the 'z' suffix of a file name, or NULL. For all
* systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
* accepted suffixes, in addition to the value of the --suffix option.
* ".tgz" is a useful convention for tar.z files on systems limited
* to 3 characters extensions. On such systems, ".?z" and ".??z" are
* also accepted suffixes. For Unix, we do not want to accept any
* .??z suffix as indicating a compressed file; some people use .xyz
* to denote volume data.
* On systems allowing multiple versions of the same file (such as VMS),
* this function removes any version suffix in the given name.
*/
local char *get_suffix(name)
char *name;
{
int nlen, slen;
char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
static char *known_suffixes[] =
{z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
#ifdef MAX_EXT_CHARS
"z",
#endif
NULL};
char **suf = known_suffixes;
if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
#ifdef SUFFIX_SEP
/* strip a version number from the file name */
{
char *v = strrchr(name, SUFFIX_SEP);
if (v != NULL) *v = '\0';
}
#endif
nlen = strlen(name);
if (nlen <= MAX_SUFFIX+2) {
strcpy(suffix, name);
} else {
strcpy(suffix, name+nlen-MAX_SUFFIX-2);
}
strlwr(suffix);
slen = strlen(suffix);
do {
int s = strlen(*suf);
if (slen > s && suffix[slen-s-1] != PATH_SEP
&& strequ(suffix + slen - s, *suf)) {
return name+nlen-s;
}
} while (*++suf != NULL);
return NULL;
}
/***************************************************************************
* Set ifname to the input file name (with a suffix appended if necessary)
* and istat to its stats. For decompression, if no file exists with the
* original name, try adding successively z_suffix, .gz, .z, -z and .Z.
* For MSDOS, we try only z_suffix and z.
* Return OK or ERROR.
*/
/*
* For MacOS:
*
* Set ifname to the input file name
*
* - we dont need to append anything
* - no stat
*/
local int get_istat( FSSpec *ifs, struct stat *sbuf)
{
Str255ToCStr( ifname, ifs->name );
errno = 0;
if ( fs_stat(ifs, sbuf) == 0)
return OK;
else
{
exit_code = ERROR;
return ERROR;
}
}
/***************************************************************************
* Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
* Sets save_orig_name to true if the file name has been truncated.
*/
local int make_ofname()
{
char *suff; /* ofname z suffix */
strcpy(ofname, ifname);
/* strip a version number if any and get the gzip suffix if present: */
suff = get_suffix(ofname);
if (decompress)
{
if (suff == NULL)
{
WARN((stderr,"%s: %s: unknown suffix -- ignored", progname, ifname));
return WARNING;
}
/* Make a special case for .tgz and .taz: */
strlwr(suff);
if (strequ(suff, ".tgz") || strequ(suff, ".taz"))
{
strcpy(suff, ".tar");
}
else
{
*suff = '\0'; /* strip the z suffix */
}
/* ofname might be changed later if infile contains an original name */
}
else /* compress */
if (suff != NULL)
{
DoStdIO(stderr, "%s: %s already has %s suffix -- unchanged",
progname, ifname, suff);
if (exit_code == OK) exit_code = WARNING;
return WARNING;
}
else
{
save_orig_name = 0;
strcat(ofname, z_suffix);
if ( macbinary == 1 )
strcat(ifname, ".bin");
} /* decompress ? */
return OK;
}
/* ========================================================================
* Check the magic number of the input file and update ofname if an
* original name was given and to_stdout is not set.
* Return the compression method, -1 for error, -2 for warning.
* Set inptr to the offset of the next byte to be processed.
* Updates time_stamp if there is one and --no-time is not used.
* This function may be called repeatedly for an input file consisting
* of several contiguous gzip'ed members.
* IN assertions: there is at least one remaining compressed member.
* If the member is a zip file, it must be the only one.
*/
local int get_method(int in) /* input file descriptor */
{
uch flags; /* compression flags */
char magic[2]; /* magic header */
ulg stamp; /* time stamp */
magic[0] = (char)get_byte();
magic[1] = (char)get_byte();
method = -1; /* unknown yet */
part_nb++; /* number of parts in gzip file */
header_bytes = 0;
last_member = RECORD_IO;
/* assume multiple members in gzip file except for record oriented I/O */
if (memcmp(magic, GZIP_MAGIC, 2) == 0
|| memcmp(magic, OLD_GZIP_MAGIC, 2) == 0)
{
method = (int)get_byte();
if (method != DEFLATED)
{
DoError(INPUT_ERR,WARN_ERR,
"%s: %s: unknown method %d -- get newer version of gzip",
progname, ifname, method);
exit_code = ERROR;
return -1;
}
work = unzip;
flags = (uch)get_byte();
if ((flags & ENCRYPTED) != 0)
{
DoError(INPUT_ERR,WARN_ERR,
"%s: %s is encrypted -- get newer version of gzip",
progname, ifname);
exit_code = ERROR;
return -1;
}
if ((flags & CONTINUATION) != 0)
{
DoError(INPUT_ERR,WARN_ERR,
"%s: %s is a a multi-part gzip file -- get newer version of gzip",
progname, ifname);
exit_code = ERROR;
if (force <= 1) return -1;
}
if ((flags & RESERVED) != 0)
{
DoError(INPUT_ERR,WARN_ERR,
"%s: %s has flags 0x%x -- get newer version of gzip",
progname, ifname, flags);
exit_code = ERROR;
if (force <= 1) return -1;
}
stamp = (ulg)get_byte();
stamp |= ((ulg)get_byte()) << 8;
stamp |= ((ulg)get_byte()) << 16;
stamp |= ((ulg)get_byte()) << 24;
if (stamp != 0 && !no_time) time_stamp = stamp + MAC_TIMEOFFSET;
(void)get_byte(); /* Ignore extra flags for the moment */
(void)get_byte(); /* Ignore OS type for the moment */
if ((flags & CONTINUATION) != 0)
{
unsigned part = (unsigned)get_byte();
part |= ((unsigned)get_byte())<<8;
}
if ((flags & EXTRA_FIELD) != 0)
{
unsigned len = (unsigned)get_byte();
len |= ((unsigned)get_byte())<<8;
while (len--) (void)get_byte();
}
/* Get original file name if it was truncated */
if ((flags & ORIG_NAME) != 0)
{
if (no_name || part_nb > 1)
{
/* Discard the old name */
char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
do {c=get_byte();} while (c != 0);
}
else
{
char *p = ofname;
char *base = p;
for (;;)
{
*p = (char)get_char();
if (*p++ == '\0') break;
if (p >= ofname+sizeof(ofname))
{
error("corrupted input -- file name too large");
}
}
/* If necessary, adapt the name to local OS conventions: */
MAKE_LEGAL_NAME(base);
/*
* it still can be too long, and is is a MacBinary file,
* it won't be the actual name, either
*/
if (base) list=0; /* avoid warning about unused variable */
} /* no_name || to_stdout */
} /* ORIG_NAME */
/* Discard file comment if any */
if ((flags & COMMENT) != 0)
{
while (get_char() != 0) /* null */ ;
}
if (part_nb == 1)
{
header_bytes = inptr + 2*sizeof(long); /* include crc and size */
}
}
else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
&& memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0)
{
/* To simplify the code, we support a zip file when alone only.
* We are thus guaranteed that the entire local header fits in inbuf.
*/
inptr = 0;
work = unzip;
if (check_zipfile(in) != OK) return -1;
/* check_zipfile may get ofname from the local header */
last_member = 1;
}
else if (memcmp(magic, PACK_MAGIC, 2) == 0)
{
work = unpack;
method = PACKED;
}
else if (memcmp(magic, LZW_MAGIC, 2) == 0)
{
work = unlzw;
method = COMPRESSED;
last_member = 1;
}
else if (memcmp(magic, LZH_MAGIC, 2) == 0)
{
work = unlzh;
method = LZHED;
last_member = 1;
}
else if (force && to_stdout && !list)
{ /* pass input unchanged */
method = STORED;
work = copy;
inptr = 0;
last_member = 1;
}
if (method >= 0) return method;
if (part_nb == 1)
{
DoError(INPUT_ERR,WARN_ERR, "%s: %s: not in gzip format", progname, ifname);
exit_code = ERROR;
return -1;
}
else
{
WARN((stderr, "%s: %s: decompression OK, trailing garbage ignored",
progname, ifname));
return -2;
}
}
/* ========================================================================
* Shorten the given name by one character, or replace a .tar extension
* with .tgz. Truncate the last part of the name which is longer than
* MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
* has only parts shorter than MIN_PART truncate the longest part.
* For decompression, just remove the last character of the name.
*
* IN assertion: for compression, the suffix of the given name is z_suffix.
*/
local void shorten_name(name)
char *name;
{
int len; /* length of name without z_suffix */
char *trunc = NULL; /* character to be truncated */
int plen; /* current part length */
int min_part = MIN_PART; /* current minimum part length */
char *p;
len = strlen(name);
if (decompress) {
if (len <= 1) error("name too short");
name[len-1] = '\0';
return;
}
p = get_suffix(name);
if (p == NULL) error("can't recover suffix");
*p = '\0';
save_orig_name = 1;
/* compress 1234567890.tar to 1234567890.tgz */
if (len > 4 && strequ(p-4, ".tar")) {
strcpy(p-4, ".tgz");
return;
}
/* Try keeping short extensions intact:
* 1234.678.012.gz -> 123.678.012.gz
*/
do {
p = strrchr(name, PATH_SEP);
p = p ? p+1 : name;
while (*p) {
plen = strcspn(p, PART_SEP);
p += plen;
if (plen > min_part) trunc = p-1;
if (*p) p++;
}
} while (trunc == NULL && --min_part != 0);
if (trunc != NULL) {
do {
trunc[0] = trunc[1];
} while (*trunc++);
trunc--;
} else {
trunc = strrchr(name, PART_SEP[0]);
if (trunc == NULL) error("internal error in shorten_name");
if (trunc[1] == '\0') trunc--; /* force truncation */
}
strcpy(trunc, z_suffix);
}
/* ========================================================================
* If compressing to a file, check if ofname is not ambiguous
* because the operating system truncates names. Otherwise, generate
* a new ofname and save the original name in the compressed file.
* If the compressed file already exists, ask for confirmation.
* The check for name truncation is made dynamically, because different
* file systems on the same OS might use different truncation rules (on SVR4
* s5 truncates to 14 chars and ufs does not truncate).
* This function returns -1 if the file must be skipped, and
* updates save_orig_name if necessary.
* IN assertions: save_orig_name is already set if ofname has been
* already truncated because of NO_MULTIPLE_DOTS. The input file has
* already been open and istat is set.
*/
/*
* MacGzip
*
* IN:
* ofname generated/extracted from .gz
* ofs = ifs
*/
#define MAXPATHLEN 31
local int check_ofname()
{
errno = 0;
while ( strlen( ofname ) > MAXPATHLEN)
shorten_name(ofname);
CStrToStr255( ofs.name, ofname );
if ( !decompress )
{
if ( noErr != (err = MakeOFSSpec( &ofs, "\pSave gzip file:" )))
{
exit_code = ERROR;
return ERROR;
}
}
return OK;
}
/* ========================================================================
* Set the access and modification times from the given stat buffer.
*/
local void reset_times (FSSpec *fs, struct stat *statb)
{
CInfoPBRec info;
info.hFileInfo.ioNamePtr = fs->name;
info.hFileInfo.ioVRefNum = fs->vRefNum;
info.hFileInfo.ioFDirIndex = 0;
info.hFileInfo.ioDirID = fs->parID;
if ( noErr != ( err = PBGetCatInfo( (CInfoPBPtr) &info, false ) ) )
{
errno = err;
}
else
{
info.hFileInfo.ioNamePtr = fs->name;
info.hFileInfo.ioVRefNum = fs->vRefNum;
info.hFileInfo.ioFDirIndex = 0;
info.hFileInfo.ioDirID = fs->parID;
info.hFileInfo.ioFlCrDat = statb->st_ctime;
info.hFileInfo.ioFlMdDat = statb->st_mtime;
err = errno = PBSetCatInfo( (CInfoPBPtr) &info, false );
}
}
/* ========================================================================
* Copy modes, times, ownership from input file to output file.
* IN assertion: to_stdout is false.
*/
local void copy_stat(ifstat)
struct stat *ifstat;
{
if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp)
{
/* buf->st_atime = info->hFileInfo.ioFlMdDat;
* buf->st_mtime = info->hFileInfo.ioFlMdDat;
* buf->st_ctime = info->hFileInfo.ioFlCrDat;
*/
ifstat->st_mtime =
ifstat->st_atime =
ifstat->st_ctime = time_stamp;
}
reset_times( &ofs, ifstat);
remove_ofname = 0;
/* It's now safe to remove the input file: */
if ( !gPrefs.Misc.KeepOriginal )
if ( fs_unlink(&ifs))
{
DoError(STDC_ERR, WARN_ERR, "Can't delete %s", ifname);
}
}
/* ========================================================================
* Free all dynamically allocated variables and exit with the given code.
*/
local void do_exit(exitcode)
int exitcode;
{
FREE(inbuf);
FREE(outbuf);
FREE(d_buf);
FREE(window);
#ifndef MAXSEG_64K
FREE(tab_prefix);
#else
FREE(tab_prefix0);
FREE(tab_prefix1);
#endif
if (exitcode==0)
{
return;
}
else
{
err = errno = noErr;
longjmp( env, exitcode );
/* this is not executed */
DoError(PROG_ERR, QUIT_ERR, "Serious fail, quitting… (%d)", exitcode );
}
}
/* ========================================================================
* Signal and error handler.
*/
RETSIGTYPE abort_gzip()
{
if (fd_busy[ifd] == 1)
{
close(ifd);
}
if ((remove_ofname) && (fd_busy[ofd] == 1))
{
close(ofd);
if ( fd_table[ofd].new == 1 )
fs_unlink (&ofs);
}
do_exit(ERROR);
}
/* ========================================================================
* init the options
*
* Input:
* - gPrefs
* - ifs
* - startup keys (in gApp.KeysMode and KeysOp)
* - Op ( from expand to, compress to)
*/
#define kAskRFID 154
#define kAskRF_mb 1
#define kAskRF_not 2
#define kAskRF_quit 3
local Boolean init_globals( FSSpec *fs )
{
/* decompress (-d) */
/*
* this can be set by:
* dropping with 'opt' => force compress
* dropping with 'ctrl' => force decompress
* or
* Menu 'Expand'/'Compress' -> Op ( keys already have modify this )
* else
* File type is 'Gzip' (or similar) / or DefaultCompress
*/
Boolean error = FALSE;
switch ( gApp.Op )
{
case kMisc_gzip:
decompress = 0;
break;
case kMisc_gunzip:
decompress = 1;
break;
case kMisc_auto:
decompress=
(( gPrefs.Misc.DefaultOp == kMisc_gunzip ) ||
(
( gPrefs.Misc.DefaultOp == kMisc_auto ) &&
(
(gSufMap.Type == 'Gzip') ||
(gSufMap.Type == 'ZIVU') ||
(gSufMap.Type == 'ZIVM') ||
(gSufMap.Type == 'pZIP')
)
));
break;
default:
DoError(PROG_ERR, QUIT_ERR, "there is a bug somewhere...");
break;
}
force = gPrefs.gzip.Force; /* don't ask questions, compress links (-f) */
no_name = -1; /* don't save or restore the original file name */
no_time = -1; /* don't save or restore the original file time */
if ( gPrefs.gzip.NoName )
no_name = no_time = 1;
if ( gPrefs.gzip.Name )
no_name = no_time = 0;
verbose = 0; /* be verbose (-v) */
quiet = 0; /* be very quiet (-q) */
maxbits = BITS; /* max bits per code for LZW */
method = DEFLATED;/* compression method */
level = (int) gPrefs.gzip.Level; /* compression level */
exit_code = OK; /* program exit code */
total_in = 0; /* input bytes for all files */
total_out = 0; /* output bytes for all files */
remove_ofname = 0; /* remove output file on error */
work = zip;
if (( gPrefs.gzip.UseCustomSuffix ) && ( decompress || (!decompress && !gPrefs.gzip.GunzipSuffix)))
{
Str255ToCStr( z_suffix, gPrefs.gzip.Suffix );
}
else
{
strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
}
z_len = strlen(z_suffix);
if ( !decompress )
{
Boolean IsText = ( gSufMap.Type == 'TEXT' );
ascii = -1; /* -1 for unknown */
macbinary = 0; /* still not declared OJO */
if (( gPrefs.Compress.Keys ) && ( gApp.KeysMode != 0 ))
{
switch ( gApp.KeysMode )
{
case kAppKeyASCII:
ascii = 1;
macbinary = 0;
break;
case kAppKeyBin:
ascii = 0;
macbinary = 0;
break;
case kAppKeyMBin:
ascii = 0;
macbinary = 1;
break;
default:
DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
break;
}
}
else
{
if ( gPrefs.Compress.IC )
{
if ( gPrefs.Compress.IC_ASCII && IsText )
{
macbinary = 0;
ascii = 1;
}
else
{
ResolveFileType( fs, nil, &gSufMap, kRFTUpload | kRFTFromSpec | kRFTIC );
if ( gSufMap.Found )
{
if ( gSufMap.MacFile && !gPrefs.Compress.IC_NotMB )
{
ascii = 0;
macbinary = 1;
}
else
{
ascii = !gSufMap.Binary;
macbinary = 0;
}
if ( IsText && gPrefs.Compress.IC_ASCII )
{
ascii = 1;
macbinary = 0;
}
}
}
}
}
if ( ascii == -1 ) /* still unresolved */
{
switch ( gPrefs.Compress.Mode )
{
case kComp_MASCII:
ascii = 1;
macbinary = 0;
break;
case kComp_MBin:
ascii = 0;
macbinary = 0;
break;
case kComp_MMB:
ascii = 0;
macbinary = 1;
break;
}
if ( (ascii == 0) && IsText && ( macbinary == 0 ) && ( gPrefs.Compress.Mode_a ) )
{
ascii = 1;
macbinary = 0;
}
}
if (( macbinary == 0 ) && ( istat.st_rsize != 0 ))
{
switch ( gPrefs.Compress.ResFork )
{
case kComp_RFAsk:
DoNotification();
ParamText(fs->name,"\p","\p","\p");
switch ( CautionAlert( kAskRFID, nil ) )
{
case kAskRF_mb:
macbinary = 1;
break;
case kAskRF_not:
break;
case kAskRF_quit:
error = TRUE;
break;
default:
DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
break;
}
break;
case kComp_RFMB:
macbinary = 1;
break;
case kComp_RFNot:
break;
case kComp_RFQuit:
error = TRUE;
break;
default:
break;
}
}
}
else /* decompress */
{
ascii = macbinary = -1;
/* we have no clue about output file */
}
return error;
}
/* ========================================================================
* Prompt for destination (compressed file)
*
*/
OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt )
{
OSErr result = noErr;
StandardFileReply sfr;
/* since this can be called from MacIO, after making some
* processing, we need to post a notification
*/
DoNotification( );
StandardPutFile(prompt, fs->name, &sfr );
if ( sfr.sfReplacing )
{
if ( 0 == memcmp( &ifs, &sfr.sfFile , sizeof(FSSpec) ) )
{
/* is this possible? */
Str255ToCStr( ofname, sfr.sfFile.name );
DoError(INPUT_ERR, WARN_ERR, "%s: cannot make %s onto itself",
progname, ofname);
return -1;
}
else
{
if (noErr != (err = FSpDelete(&sfr.sfFile)))
{
Str255ToCStr( ofname, sfr.sfFile.name );
DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
return err;
}
else
{
*fs = sfr.sfFile;
}
}
}
else if ( sfr.sfGood )
{
Str255ToCStr( ofname, sfr.sfFile.name );
*fs = sfr.sfFile;
}
else
{
result = -1;
}
return result;
}
OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt )
{
StandardFileReply sfr;
Boolean done;
FSSpec fSpec;
Boolean changedFlag;
struct stat fldrStat;
done = TRUE;
if ( gApp.Prompt )
{
if ( noErr != ( err = PromptGZIPFile( fs, prompt )) )
return err;
}
else if ( gPrefs.Folder.UseDestFolder && ( nil != gApp.DFolder ))
{
if( noErr == (err = ResolveAlias(nil, gApp.DFolder, &fSpec, &changedFlag)))
{
err = fs_stat( &fSpec, &fldrStat );
if (( S_ISDIR ( fldrStat.st_mode ) ) && ( noErr == err ))
{
fs->vRefNum = fldrStat.st_dev;
fs->parID = fldrStat.st_ino;
}
}
if (noErr != err)
{
/* display alert and prompt for new destination */
/* unset use folder too */
DoError( SYS_ERR, WARN_ERR, "Sorry, Can't find your destination folder");
gPrefs.Folder.UseDestFolder = FALSE;
if ( noErr != PromptGZIPFile( fs, prompt ) )
return err;
}
else
{
done = FALSE;
}
}
else
done = FALSE;
if ( !done )
{
/* replace if force, else prompt */
FInfo foo;
err = FSpGetFInfo ( fs, &foo );
if ( err != fnfErr )
{
if( err != noErr )
{
return err;
}
/* ofs exists */
else if ( gPrefs.gzip.Force )
{
if (noErr != (err = FSpDelete(&sfr.sfFile)))
{
Str255ToCStr( ofname, sfr.sfFile.name );
DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
return err;
}
}
else
{
if ( noErr != (err = PromptGZIPFile( fs, prompt )) )
{
return err;
}
}
}
}
return noErr;
}